package com.budwk.app.sys.services.impl;

import cn.hutool.extra.ssh.JschUtil;
import com.budwk.app.base.gmpass.SM4Util;
import com.budwk.app.common.component.LinuxPackageLayComponent;
import com.budwk.app.common.config.AppException;
import com.budwk.app.sqfw.constants.CommonConstants;
import com.budwk.app.sys.models.LinuxServiceLayConfig;
import com.budwk.app.sys.services.LinuxServicelayConfigService;
import com.budwk.app.sys.vo.LinuxServiceLayConfigVo;
import com.budwk.app.util.JschLinuxUtil;
import com.budwk.starter.common.page.Pagination;
import com.budwk.starter.common.result.Result;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.budwk.starter.security.utils.SecurityUtil;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.sql.Criteria;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.loader.annotation.IocBean;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.time.LocalDateTime;

@Slf4j
@IocBean(args = {"refer:dao"})
public class LinuxServiceLayConfigServiceImpl extends BaseServiceImpl<LinuxServiceLayConfig> implements LinuxServicelayConfigService {
    public LinuxServiceLayConfigServiceImpl(Dao dao) {
        super(dao);
    }


    /**
     * jsch创建连接
     * @return
     */
    @Override
    public Session getJSchSession(LinuxServiceLayConfig config){
        Session session = null;
        try {
            session = JschLinuxUtil.getJSchSession(config);;
            return session;
        } catch (Exception e) {
            log.error("getJSchSession error: ", e);
            LinuxPackageLayComponent.closeSession(session);
            throw new AppException("获取连接失败，请稍后重试！");
        }
    }

    @Override
    public boolean uploadFile(Session sshSession, File uploadFile, String linuxServiceLayConfigId, String backFileName, String uploadFileName) {
        LinuxServiceLayConfig config = fetch(linuxServiceLayConfigId);
        if (config == null) {
            throw new AppException("请先配置服务器");
        }
        log.info("文件正在上传中，请等待......");
        boolean isSuccess = false;
        InputStream is = null;
        File file = null;
        ChannelSftp sftp = null;
        boolean isBack = false; // 是否备份
        try {
            sftp = JschLinuxUtil.getSftpSession(sshSession);
            // 1 先备份文件
            if (StringUtils.isNotEmpty(backFileName)) {
                renameFile(config.getFileUploadPath(), uploadFileName, backFileName, sftp);
                isBack = true;
            }
            // 2 上传
            file = new File(uploadFile.getPath().substring(0, uploadFile.getPath().lastIndexOf(File.separator)) + File.separator + uploadFileName);
            FileUtils.copyFile(uploadFile, file);
            sftp.cd(config.getFileUploadPath());
            String fileName = file.getName();
            is = new FileInputStream(file);
            sftp.put(is, fileName, ChannelSftp.OVERWRITE);//有重名文件覆盖
            log.info("文件上传结束");
            isSuccess = true;
        } catch (Exception e) {
            log.error("linux upload File error:", e);
            isSuccess = false;
            return false;
        } finally {
            IOUtils.closeQuietly(is);
            uploadFile.delete();
            if (file != null) {
                file.delete();
            }
            if (!isSuccess && isBack) {
                // 上传失败，需要将原文件改名过来
                renameFile(config.getFileUploadPath(), backFileName, uploadFileName, sftp);
            }
            LinuxPackageLayComponent.closeSession(sshSession);
            LinuxPackageLayComponent.closeChannelSftp(sftp);
        }
        return isSuccess;
    }

    public void renameFile(String directory, String oldname, String newname, ChannelSftp sftp) {
        try {
            sftp.cd(directory);
            sftp.rename(oldname, newname);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Result<?> listConfigByPage(LinuxServiceLayConfigVo layVo) {
        Criteria cri = Cnd.cri();
        SqlExpressionGroup criSql = cri.where();
        Pagination pagination = listPage(layVo.getPageNo(), layVo.getPageSize(), cri);
        return Result.data(pagination);
    }

    @Override
    public Result<?> addConfigInfo(LinuxServiceLayConfig layVo) {
        layVo.setCreateId(SecurityUtil.getUserId())
                .setCreateTime(LocalDateTime.now())
                .setPassword(SM4Util.encryptEcb(CommonConstants.GENERKEY_PASSWORD, layVo.getPassword()));
        this.insert(layVo);
        return Result.success();
    }

    @Override
    public Result<?> updateConfigInfo(LinuxServiceLayConfig layVo) {
        if (StringUtils.isNotEmpty(layVo.getPassword())) {
            layVo.setPassword(SM4Util.encryptEcb(CommonConstants.GENERKEY_PASSWORD, layVo.getPassword()));
        }
        updateIgnoreNull(layVo);
        return Result.success();
    }

    @Override
    public void executeShell(Session session, String command) {
        String out = "";
        try {
            out = JschUtil.exec(session, command, Charset.defaultCharset());
        } catch (Exception e) {
            log.error("executeShell error: ", e);
            throw new AppException();
        } finally {
            LinuxPackageLayComponent.closeSession(session);
        }
        log.info("-------------------发布执行结果为：{} ", out);
    }
}
